#include <iostream>
#include <assert.h>
using namespace std;

#define SIXTEEN

#if defined ONE

class Box
{
public:
    double length;
    double breadth;
    double height;

    // 下面的成员函数，是在类内 声明函数原型  然后在类外实现函数
    double Get(void);
    void   Set(double len, double bre, double hei);
};

double Box::Get(void)
{
    return length * breadth * height;
}

void Box::Set(double len, double bre, double hei)
{
    length  = len;
    breadth = bre;
    height  = hei;
}

int main(void)
{
    Box Box1;
    Box Box2;
    Box Box3;

    double volume = 0.0;

    Box1.height   = 5.0;
    Box1.length   = 6.0;
    Box1.breadth  = 7.0;

    Box2.height   = 10.0;
    Box2.length   = 12.0;
    Box2.breadth  = 13.0;

    volume        = Box1.height * Box1.length * Box1.breadth;

    cout << "Box1 的体积: " << volume << endl;

    volume = Box2.height * Box2.length * Box2.breadth;

    cout << "Box2 的体积: " << volume << endl;

    Box3.Set(16.0, 8.0, 12.0);

    cout << "Box3 的体积: " << Box3.Get() << endl;

    return 0;
}
#elif defined TWO

class Box
{
private:   // class里面成员的访问修饰符，默认是private
    double length;
    double breadth;
    double height;

public:
    double GetVolume(void);
    void   SetLength(double len);
    void   SetBreadth(double bre);
    void   SetHeight(double hei);
};

double Box::GetVolume(void)
{
    return length * breadth * height;
}

void Box::SetLength(double len)
{
    length = len;
}

void Box::SetBreadth(double bre)
{
    breadth = bre;
}

void Box::SetHeight(double hei)
{
    height = hei;
}

int main(void)
{
    Box Box1;
    Box Box2;

    Box1.SetLength(6.0);
    Box1.SetBreadth(7.0);
    Box1.SetHeight(5.0);

    Box2.SetLength(12.0);
    Box2.SetBreadth(13.0);
    Box2.SetHeight(10.0);

    cout << "Box1的体积: " << Box1.GetVolume() << endl;
    cout << "Box2的体积: " << Box2.GetVolume() << endl;
}

#elif defined THREE

class Box
{
public:
    double length;
    void   SetWidth(double width);
    double GetWidth(void);

private:
    double width;
};

void Box::SetWidth(double width)
{
    width = width;
}

double Box::GetWidth(void)
{
    return width;
}

int main(void)
{
    Box box;

    box.length = 10.0;
    cout << "Length Of Box: " << box.length << endl;

    // box.width=10.0;
    box.SetWidth(10.0);
    cout << "Width Of Box: " << box.GetWidth() << endl;

    return 0;
}

#elif defined FOUR

class Box
{
protected:   // 在子类里面是可以访问的
    double width;
};

// 注意这里 SmallBox继承Box
class SmallBox : Box
{
public:
    void   SetSmallBoxWidth(double wid);
    double GetSmallWidth(void);
};

void SmallBox::SetSmallBoxWidth(double wid)
{
    // 左边的width是父类里面的 成员变量
    width = wid;   // 这里的形参 最好不要和类的成员变量同名
}

double SmallBox::GetSmallWidth(void)
{
    return width;
}

int main(void)
{
    SmallBox box;

    box.SetSmallBoxWidth(5.0);
    cout << "Width Of Box:" << box.GetSmallWidth() << endl;

    return 0;
}

#elif defined FIVE

class A
{
public:
    int a;   // 这个事public类型的
    A()
    {   // 这个函数是构造函数
        a1 = 1;
        a2 = 2;
        a3 = 3;
        a  = 4;
    }
    void fun()
    {
        cout << a << endl;
        cout << a1 << endl;
        cout << a2 << endl;
        cout << a3 << endl;
    }

public:
    int a1;

protected:
    int a2;

private:
    int a3;
};

// 研究类之间的继承关系，只需要在后面的 public protected private 三种关键字之间选一个
class B : public A
{
public:
    int a;
    B(int i)
    {   // 这个函数是构造函数
        A();
        a = i;
    }
    void fun()
    {
        cout << a << endl;
        cout << a1 << endl;
        cout << a2 << endl;
        // cout << a3 << endl;  //错误，基类的private成员不能被派生类访问
    }
};

int main(void)
{
    B b(10);   // 定义对象的同时，调用了构造函数对这个对象进行初始化

    cout << b.a << endl;
    cout << b.a1 << endl;
    // cout << b.a2 << endl;  //错误,类外不能访问protected 成员
    // cout << b.a2 << endl;  //错误,类外不能访问private 成员

    system("pause");
    return 0;
}

#elif defined SIX

class Line
{
public:
    void   SetLength(double Len);
    double GetLength(void);
    Line();   // 类的构造函数不会返回任何类型，也不会返回void

private:
    double Length;
};

/**
 * 这里的写法注意了
 */
void Line::SetLength(double Len)
{
    Length = Len;
    cout << "Length = Len" << endl;
}

double Line::GetLength(void)
{
    return Length;
}

Line::Line()
{
    cout << "Object Is Being Created" << endl;
}

int main(void)
{
    Line line;

    line.SetLength(6.0);

    cout << "Length Of Line :" << line.GetLength() << endl;

    return 0;
}

#elif defined SEVEN

class Line
{
public:
    void   SetLength(double Len);
    double GetLength(void);
    double GetWidth(void);
    double GetHeight(void);
    Line(double Len);   // 这是构造函数
    Line(double Len, double Wid);
    Line(double Len, double Wid, double Hei);

    // 上面涉及到了函数的重载 参考 Function.cpp文件

private:
    double Length;
    double Width;
    double Height;
    double Volume;
};   // 注意这里是有一个 ;号的

void Line::SetLength(double Len)
{
    Length = Len;
}

double Line::GetLength(void)
{
    return Length;
}

double Line::GetWidth(void)
{
    return Width;
}

double Line::GetHeight(void)
{
    return Height;
}

Line::Line(double Len)
{
    cout << "Object Is Being Created , Length=" << Len << endl;
    Length = Len;
}

Line::Line(double Len, double Wid)
{
    Length = Len;
    Width  = Wid;
}

/**
 * 注意区分上下两种写法
 * 其实都是可以的
 */

Line::Line(double Len, double Wid, double Hei) : Length(Len), Width(Wid), Height(Hei) {}

int main(void)
{
    Line line(10.0, 20.0, 33.3);

    cout << "Length Of Line :" << line.GetLength() << endl;
    cout << "Width Of Line :" << line.GetWidth() << endl;
    cout << "Height Of Line :" << line.GetHeight() << endl;
    line.SetLength(6.0);
    cout << "Length Of Line :" << line.GetLength() << endl;

    return 0;
}

#elif defined EIGHT

class Line
{
public:
    void   SetLength(double Len);
    double GetLength(void);
    Line();    // 构造函数声明
    ~Line();   // 析构函数声明

private:
    double Length;
};

// 构造函数的定义
Line::Line(void)
{
    cout << "Object Is Being Created" << endl;
}

Line::~Line(void)
{
    cout << "Object Is Being Deleted" << endl;
}

double Line::GetLength(void)
{
    return Length;
}

void Line::SetLength(double Len)
{
    Length = Len;
}

int main(void)
{
    Line line;   // 这个类的对象实例，只是在栈里面(其实就是局部变量)

    line.SetLength(6.0);
    cout << "Length Of Line : " << line.GetLength() << endl;

    return 0;
}

#elif defined NINE

class Line
{
public:
    int GetLength(void);
    Line(int Len);           // 简单构造函数
    Line(const Line& obj);   // 拷贝构造函数  const表示引用内容不可更改
    ~Line();                 // 析构函数
    // 上面仅仅是成员函数声明

private:
    int* Ptr = NULL;
};

// 下面是成员函数定义
Line::Line(int Len)
{
    cout << "调用构造函数" << endl;
    // 为指针分配内存   具体参见 Array.cpp
    Ptr  = new int(0);   // 相当于直接初始化为0

    *Ptr = Len;
}

// 这里是拷贝构造函数  obj就是实参的别名    复制对象把它作为参数传递给函数
Line::Line(const Line& obj)
{
    cout << "调用拷贝构造函数为指针Ptr分配内存" << endl;
    Ptr  = new int(0);
    *Ptr = *obj.Ptr;   // 拷贝值
}

// 注意析构函数参数为void,没有返回值
Line::~Line(void)
{
    cout << "释放内存" << endl;
    delete Ptr;
}

int Line::GetLength(void)
{
    return *Ptr;
}

void Display(Line obj)
{
    cout << "line大小: " << obj.GetLength() << endl;
}

/**
 * 拷贝构造函数的机理是啥
 */
int main(void)
{
    Line line(10);

    Display(line);

    return 0;
}

#elif defined TEN

class Line
{
public:
    int GetLength(void);
    Line(int Len);           // 简单构造函数
    Line(const Line& obj);   // 拷贝构造函数
    ~Line();                 // 析构函数

private:
    int* Ptr;
};

// 构造函数是没有返回值的
Line::Line(int Len)
{
    cout << "调用构造函数" << endl;
    Ptr  = new int;
    *Ptr = Len;
}

Line::Line(const Line& obj)
{
    cout << "调用拷贝构造函数并为指针Ptr分配内存" << endl;
    Ptr  = new int;
    *Ptr = *obj.Ptr;   // 复制值
}

Line::~Line(void)
{
    cout << "释放内存" << endl;
    delete Ptr;
}

int Line::GetLength(void)
{
    return *Ptr;
}

void Display(Line obj)
{
    cout << "Line大小:" << obj.GetLength() << endl;
}

int main(void)
{
    Line line1(10);
    Line line2 = line1;   // 这里也调用了拷贝构造函数

    Display(line1);
    Display(line2);

    return 0;
}

#elif defined ELEVEN

class Box
{
private:
    double Width;

public:
    friend void PrintWidth(Box box);   // 这个类的友元函数
    void        SetWidth(double Wid);
};

void Box::SetWidth(double Wid)
{
    Width = Wid;
}

// 注意这个函数不是任何类的成员函数，所以函数名称前面就没有  Box::
void PrintWidth(Box box)
{
    // 因为 PrintWidth 是类 Box的友元，所以它可以直接访问该类的任何成员
    cout << "Width Of Box :" << box.Width << endl;
}

int main(void)
{
    Box box;

    box.SetWidth(10.0);

    PrintWidth(box);

    return 0;
}

#elif defined TWELVE

class MyClass
{
private:
    int Value;

public:
    void SetValue(int value)
    {
        // 当前对象的成员变量
        this->Value = value;
    }
    void PrintValue(void)
    {
        cout << "Value: " << this->Value << endl;
    }
};

int main(void)
{
    MyClass obj;

    obj.SetValue(42);
    obj.PrintValue();

    return 0;
}

#elif defined THIRTEEN

class Box
{
public:
    Box(double l = 2.0, double b = 2.0, double h = 2.0)   // 构造函数，并且构造函数的形参都有缺省值
    {
        cout << "调用构造函数" << endl;
        Length  = l;
        Breadth = b;
        Height  = h;
    }
    // 其它对象和本对象比较
    int Compare(Box box)
    {   // 在类的成员函数里面使用this指针
        return this->Volume() > box.Volume();
    }
    double Volume(void)
    {
        return Length * Breadth * Height;
    }

private:
    double Length;
    double Breadth;
    double Height;
};

int main(void)
{
    Box box1(3.3, 1.2, 1.5);
    Box box2(8.5, 6.0, 2.0);

    if (box1.Compare(box2))
    {
        cout << "box1的体积大于box2的体积" << endl;
    }
    else
    {
        cout << "box2的体积大于等于box1" << endl;
    }
    return 0;
}

#elif defined FOURTEEN

class Box
{
public:
    Box(double l = 2.0, double b = 2.0, double h = 2.0)
    {
        cout << "调用了构造函数" << endl;
        Length  = l;
        Breadth = b;
        Height  = h;
    }
    double Volume(void)
    {
        return Length * Breadth * Height;
    }

private:
    double Length;
    double Breadth;
    double Height;
};

int main(void)
{
    Box  box1(3.3, 1.2, 1.5);
    Box  box2(8.5, 6.0, 2.0);
    Box* PtrBox = nullptr;

    PtrBox      = &box1;
    cout << "Volume Of Box1: " << PtrBox->Volume() << endl;
    PtrBox = &box2;
    cout << "Volume Of Box1: " << PtrBox->Volume() << endl;

    return 0;
}

#elif defined FIFTEEN

class Box
{
public:
    static int ObjectCounter;   // static 如果要在声明时赋一个默认值，那么它必须 在前面加一个 const  也就是 const static int
    Box(double l = 2.0, double b = 2.0, double h = 2.0)
    {
        cout << "调用了构造函数" << endl;
        Length  = l;
        Breadth = b;
        Height  = h;
        ObjectCounter++;   // 每次创建对象增加1
    }
    double Volume(void)
    {
        return Length * Breadth * Height;
    }

private:
    double Length;
    double Breadth;
    double Height;
};

// 注意这里是关键  初始化类Box的静态成员
int Box::ObjectCounter = 0;   // ::叫做域解析运算符

int main(void)
{
    Box box1(3.3, 1.2, 1.5);
    Box box2(8.5, 6.0, 2.0);

    cout << "Total Objects: " << Box::ObjectCounter << endl;

    return 0;
}

#elif defined SIXTEEN

class Box
{
public:
    static int ObjCounter;   // 记住这里没有对静态成员变量进行初始化
    Box(double l, double b, double h);
    double     Volume(void);
    static int GetCount(void);

private:
    double Length;
    double Breadth;
    double Height;
};

int Box::ObjCounter = 0;   // 类里面静态成员变量的初始化

// 类的构造函数  下面给函数的形式参数 默认值了
Box::Box(double l = 2.0, double b = 2.0, double h = 2.0)
{
    cout << "调用构造函数" << endl;
    Length  = l;
    Breadth = b;
    Height  = h;
    ObjCounter++;
}

double Box::Volume(void)
{
    return Length * Breadth * Height;
}

// 记住静态成员函数只能访问静态成员变量，其它静态成员函数，和类外部的其它函数
int Box::GetCount(void)
{
    return ObjCounter;
}

int main(void)
{
    cout << "Initial Stage Count: " << Box::GetCount() << endl;
    Box box1(3.3, 1.2, 1.5);
    Box box2(8.5, 6.0, 2.0);
    cout << "Final Stage Count:: " << Box::GetCount() << endl;

    return 0;
}

#elif defined SEVENTEEN

#elif defined EIGHTEEN

#endif

/**
 *  C++ 在 C 语言的基础上增加了面向对象编程，C++ 支持面向对象程序设计。类是 C++ 的核心特性，通常被称为用户定义的类型。
 *  类用于指定对象的形式，是一种用户自定义的数据类型，它是一种封装了数据和函数的组合。类中的数据称为成员变量，函数称为
 *  成员函数。类可以被看作是一种模板，可以用来创建具有相同属性和行为的多个对象
 *
 *  类提供了对象的蓝图,所以基本上,对象是根据类来创建的,可以参照结构体
 *
 *  C++类中成员函数的实现主要有两种方式
 *  1.类内实现(隐式inline)
 *    直接在类内部编写函数体
 *    会被编译器自动视为inline函数建议（实际是否内联由编译器决定)
 *    适合简单、短小的函数实现
 *
 *  2.类外实现（需作用域解析）
 *    类内声明函数原型，类外通过类名::实现
 *    必须使用作用 域解析运算符(也可以理解为范围解析运算符)::  明确函数归属
 *    适合复杂函数或需要分离声明/实现的场景
 *
 *  关键区别：
 *    类内实现更紧凑，类外实现更清晰
 *    类外实现可以避免头文件污染
 *    模板函数必须在头文件中实现
 *    虚函数通常建议在类外实现
 *
 *  最佳实践：
 *    简单getter/setter在类内实现
 *    复杂业务逻辑在类外实现
 *    保持一致性（同一类中统一风格）
 *
 *  私有的成员和受保护的成员不能 使用直接成员访问运算符(.)来访问
 *
 *  数据封装是面向对象编程的一个重要特点,他防止函数直接访问类类型的内部成员。
 *
 *  私有(private)成员
 *    私有成员变量或者函数在类的外部是不可访问的，甚至是不可查看的。只有类和友元函数可以访问私有成员
 *    默认情况下,类的所有成员都是私有的
 *
 *  实际操作中，我们一般会在私有区域定义数据。在共有区域定义相关的函数(就是使用这些共有的函数，操作私有的数据),以便在类的外部也可以调用这些函数
 *
 *  protected 即受保护的成员变量或者成员函数 与私有成员十分相似 ，但有一点不同,protected成员在派生类(即子类)中是可以访问的
 *
 *  类之间继承的特点   类之间默认是private继承(并且类里面的成员默认访问属性也是private)    struct之间默认是public继承(并且struct里面的成员默认访问属性也是public)  
 *     1.public     继承   基类 public 成员，protected 成员，private 成员的访问属性在派生类(记住关键)中分别变成：public, protected, private
 *     2.protected  继承   基类 public 成员，protected 成员，private 成员的访问属性在派生类(记住关键)中分别变成：protected, protected, private
 *     3.private    继承   基类 public 成员，protected 成员，private 成员的访问属性在派生类(记住关键)中分别变成：private, private, private
 *          说明在派生类里面是可以访问的(就是说原本的public属性在派生类里面变成了private)
 *     上面像是一个漏斗
 *    无论哪种继承方式，一下两点都没有改变
 *    1.private成员只能被本类成员(类内)和友元访问，不能被派生类访问
 *    2.protected成员可以被派生类访问，但是不能在类外访问派生类成员
 *
 *
 *  类的构造函数是类的一种特殊的成员函数，它会在每次创建类的新对象时执行
 *  构造函数的名称与类的名称是完全相同的，并且不会返回任何类型，也不会返回 void。构造函数可用于为某些成员变量设置初始值
 *
 *  类的析构函数是类的一种特殊的成员函数，它会在每次删除所创建的对象时执行
 *  析构函数的名称与类的名称是完全相同的，只是在前面加了个波浪号（~）作为前缀，它不会返回任何值，也不能带有任何参数(就是void类型  和构造函数的区别)
 *  析构函数有助于在跳出程序（比如关闭文件、释放内存等）前释放资源
 *
 *  拷贝构造函数是一种特殊的构造函数，它在创建对象时，是使用同一类中之前创建的对象来初始化新建的对象。构造函数通常用于
 *    1.通过使用另一个同类型的对象来初始化新创建的对象
 *    2.复制对象把它作为参数传递给函数
 *    3.复制对象，并从函数返回这个对象
 *  如果在类中没有定义拷贝构造函数，编译器会自行定义一个。如果类带有指针变量，并有动态内存分配，则它必须有一个拷贝构造函数(what ??)
 *  拷贝构造函数的最常见形式如下:
 *      classname (const classname &obj)
 *      {
 *          //构造函数的主体
 *          //上面的形参obj是一个对象引用，该对象是用来初始化另一个对象的
 *      }
 *    感觉拷贝构造函数有点难理解
 *
 *
 *  类的友元函数是定义在类外部，但有权限访问类的所有私有成员(private)和保护成员(protected)。尽管友元函数的原型有在类的定义中出现过，但是
 *  友元函数并不是成员函数
 *  友元可以是一个函数，该函数被称为友元函数；友元也可以是一个类，该类被称为友元类，在这种情况下，整个类及其所有成员都是友元
 *
 *  C++的this指针,是一个特殊的指针,它指向当前对象的实例
 *  在C++里面，每个对象都能通过this指针来访问自己的地址
 *  this是一个隐藏的指针，可以在类的成员函数中使用，它可以用来指向调用对象
 *  当一个对象的成员函数被调用时，编译器会隐式地传递该对象的地址作为 this 指针
 *  友元函数没有 this 指针(重点)，因为友元不是类的成员，只有成员函数才有 this 指针
 *
 *  C++类的静态成员变量(似乎可以看成是全局变量)
 *      我们可以使用 static 关键字来把类成员定义为静态的。当我们声明类的成员为静态时,
 *   ，这意味着无论创建多少个类的对象，静态成员都只有一个副本。
 *   静态成员在类的所有对象中是共享的。如果不存在其他的初始化语句，在创建第一个对象时，
 *   所有的静态数据都会被初始化为零。我们不能把静态成员的初始化放置在类的定义中(重点，也就是说，静态成员的初始化要放在类外部)，
 *   但是可以在类的外部通过使用范围解析运算符 :: 来重新声明静态变量从而对它进行初始化
 *
 *  C++类的静态成员函数
 *      如果把函数成员声明为静态的，就可以把函数与类的任何特定对象独立开来，静态成员函数即使在类对象不存在的情况下也能被调用(重点)
 *  反过来说，就算是类对象存在，也可以访问静态成员函数
 *  静态函数只要使用类名加范围解析运算符 :: 就可以访问  类对象.静态成员函数(这样也可以访问)
 *  静态成员函数只能访问静态成员数据、其他静态成员函数和类外部的其他函数(就是说自己类内部，只能访问静态的成员)
 *  静态成员函数有一个类范围，他们不能访问类的 this 指针。可以使用静态成员函数来判断类的某些对象是否已被创建
 *
 *          静态成员函数 和 普通成员函数的区别
 *     1.静态成员函数没有 this 指针，只能访问静态成员（包括静态成员变量和静态成员函数）
 *     2.普通成员函数有 this 指针，可以访问类中的任意成员；而静态成员函数没有 this 指针
 *
 */

/**
 * C++中,构造函数的访问属性决定了对象的创建权限(关键)，主要分为以下三种情况
 * 1.public构造函数
 *      允许类外部直接创建对象，是最常见的访问级别
 *      派生类可以调用基类的public构造函数
 *
 * 2.protected构造函数
 *      仅允许派生类创建基类对象，常用于抽象基类设计
 *      外部代码无法直接实例化该类
 *
 * 3.private构造函数
 *     完全禁止外部和派生类实例化，通常用于单例模式
 *     必须通过静态成员函数提供对象创建接口 (what？？？)
 *
 * 关键特性
 *     构造函数默认访问属性与类成员相同（class默认为private，struct默认为public）
 *     析构函数必须为public(关键)，否则会导致对象销毁时编译错误
 *     访问属性影响继承体系中的对象构造链，派生类需通过初始化列表调用可访问的基类构造函数
 * 
 * 
 *  一个派生类继承了所有的基类方法，但是下列情况除外:
 *      基类的构造函数,析构函数和拷贝构造函数
 *      基类的重载运算符
 *      基类的友元函数
 *      
 */ 
